package org.example;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.*;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.geometry.Insets;

import javafx.util.Duration;
import javafx.util.converter.IntegerStringConverter;
import org.apache.hadoop.hbase.client.Connection;

import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.function.UnaryOperator;

import com.dansoftware.pdfdisplayer.PDFDisplayer;

public class HBaseExplorer extends Application {
  private Connection conn;
  private ImageView checkmarkImageView = new ImageView();
  private VBox vbox = new VBox();
  private TextArea tableNamesTextArea = new TextArea();
  private TableView<String> tableNamesTableView = new TableView<>();
  private Timeline timeoutTimeline;
  private Task<List<String>> connectTask;
  ComboBox<String> namespaceComboBox = new ComboBox<>();

  Dialog<String> createDialog = new Dialog<>();

  public static void main(String[] args) {
    launch(args);
    System.exit(0);
  }

  @Override
  public void start(Stage primaryStage) {
    Button connectButton = new Button("Connect to HBase");

    // 加载绿色对号的图像
    Image checkmarkImage = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/success.png")));
    checkmarkImageView.setImage(checkmarkImage);
    checkmarkImageView.setFitWidth(20);
    checkmarkImageView.setFitHeight(20);
    checkmarkImageView.setVisible(false);

    connectButton.setOnAction(event -> {
      // 连接按钮点击事件处理
      connectTask = createConnectTask();
      new Thread(connectTask).start(); // 在后台线程中执行连接操作
    });

    tableNamesTableView.setFixedCellSize(24);
    tableNamesTableView.getColumns().clear();

    // 创建序号列
    TableColumn<String, Integer> indexColumn = new TableColumn<>("序号");
    indexColumn.setCellValueFactory(cellData -> new ReadOnlyObjectWrapper<>(tableNamesTableView.getItems().indexOf(cellData.getValue()) + 1));
    indexColumn.setSortable(false);
    indexColumn.setPrefWidth(50);

    // 创建表名列
    TableColumn<String, String> tableNameColumn = new TableColumn<>("表名");
    tableNameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue()));
    tableNameColumn.setPrefWidth(250);

    // 创建查询列
    TableColumn<String, String> searchColumn = new TableColumn<>("查询");
    searchColumn.setSortable(false);
    searchColumn.setPrefWidth(80);
    // 添加事件监听器，点击图标时弹出对话框并获取查询条件
    searchColumn.setCellFactory(col -> new TableCell<String, String>() {
      @Override
      protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
          setGraphic(null);
          setPrefHeight(24); // 设置空行的高度为 24
        } else {
          ImageView searchIcon = new ImageView(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/search.png"))));
          searchIcon.setFitWidth(16);
          searchIcon.setFitHeight(16);

          Button searchButton = new Button("", searchIcon);
          searchButton.setStyle("-fx-background-color: transparent; -fx-border-color: transparent;");
          searchButton.setOnAction(event -> {
            String tableName = getTableView().getItems().get(getIndex());
            showSearchDialog(tableName);
          });

          searchButton.setOnMouseEntered(event -> searchButton.setCursor(Cursor.HAND));

          setPrefHeight(24);

          // 使用 StackPane 将 searchButton 居中显示
          StackPane stackPane = new StackPane();
          stackPane.getChildren().add(searchButton);
          StackPane.setAlignment(searchButton, Pos.CENTER);

          setGraphic(stackPane);
        }
      }
    });

    // 将列添加到表格中
    tableNamesTableView.getColumns().addAll(indexColumn, tableNameColumn, searchColumn);

    namespaceComboBox.setOnAction(event -> {
      String selectedNamespace = namespaceComboBox.getSelectionModel().getSelectedItem();
      if (selectedNamespace != null) {
        // 在这里实现列出命名空间中的表的功能
        System.out.println("Tables in namespace " + selectedNamespace + ":");
        // TODO: 查询并列出命名空间中的表
        List<String> tableNames = HBaseMain.listTables(selectedNamespace); // 获取选定命名空间下的所有表名

        String tableNamesString = String.join("\n", tableNames); // 将表名拼接为一个字符串，每个表名一行
        // 清除文本框内容
        tableNamesTextArea.clear();
        // 设置新内容
        tableNamesTextArea.setText(tableNamesString);

        // 设置表格数据
        tableNamesTableView.setItems(FXCollections.observableArrayList(tableNames));
      }
    });

    HBox hbox = new HBox(10, connectButton, checkmarkImageView);
    //hbox.setPadding(new Insets(10, 10, 10, 10)); // 设置HBox的内边距

    // 添加新建表按钮
    Button newTableButton = new Button();
    Image newTableIcon = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/plus-circle-fill.png"))); // 假设按钮图标的文件名为 new_table_icon.png
    ImageView imageView = new ImageView(newTableIcon);
    imageView.setFitWidth(15); // 调整图标的宽度
    imageView.setFitHeight(15); // 调整图标的高度
    newTableButton.setGraphic(imageView);
    newTableButton.setText("新建表");
    setCreateDialog();
    newTableButton.setOnAction(event -> {
      // 在这里处理点击新建表按钮的逻辑，弹出对话框等
      createDialog.show();
    });

    HBox hboxMiddle = new HBox(10, namespaceComboBox, newTableButton);
    HBox.setHgrow(newTableButton, Priority.ALWAYS);

    vbox = new VBox(10, hbox, hboxMiddle);
    vbox.setPadding(new Insets(10, 10, 10, 10)); // 设置VBox的内边距

//    vbox.getChildren().add(tableNamesTextArea);
    vbox.getChildren().add(tableNamesTableView);


    Scene scene = new Scene(vbox, 500, 400);

    primaryStage.setTitle("HBase Explorer");
    primaryStage.setScene(scene);
    primaryStage.show();

    // 设置超时计时器
    timeoutTimeline = new Timeline(new KeyFrame(Duration.seconds(10), e -> {
      // 超时处理
      connectTask.cancel(); // 取消连接任务
      showTimeoutAlert();
    }));
    timeoutTimeline.setCycleCount(1); // 设置只执行一次
  }

  private Task<List<String>> createConnectTask() {
    return new Task<List<String>>() {
      @Override
      protected List<String> call() throws Exception {
        List<String> namespaces = null;
        try {
          // 连接操作开始时启动计时器
          timeoutTimeline.play();
          // 连接 HBase，此处为示例，需要替换为实际的连接方法
          namespaces = HBaseMain.listNamespaces();
        } finally {
          // 连接操作完成时停止计时器
          timeoutTimeline.stop();
        }
        // 连接成功，更新界面
        updateUI(namespaces);
        return namespaces;
      }

      private void updateUI(List<String> namespaces) {
        checkmarkImageView.setVisible(true);
        namespaceComboBox.setItems(FXCollections.observableArrayList(namespaces));
        namespaceComboBox.setDisable(false);
      }
    };
  }

  private void showTimeoutAlert() {
    Platform.runLater(() -> {
      Alert alert = new Alert(Alert.AlertType.WARNING);
      alert.setTitle("超时");
      alert.setHeaderText("连接超时");
      alert.setContentText("无法连接到 HBase。请稍后重试。");
      alert.showAndWait();
    });
  }

  @Override
  public void stop() throws Exception {
    super.stop();
    HBaseMain.close();
    int i = 0;
  }

  private void setCreateDialog() {
    createDialog.setTitle("新建表");
    createDialog.setHeaderText("Create HBase Table");

    // 设置对话框按钮
    ButtonType loginButtonType = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
    createDialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL);

    // 创建布局及控件
    GridPane grid = new GridPane();
    grid.setHgap(10);
    grid.setVgap(10);
    grid.setPadding(new Insets(20));

    TextField tableNameField = new TextField();
    tableNameField.setPromptText("请输入表名");
    TextField numRegionsField = new TextField();
    numRegionsField.setPromptText("请输入预分区数");

    // 创建一个整数格式化器，限制用户输入为整数
    UnaryOperator<TextFormatter.Change> filter = change -> {
      String text = change.getText();
      if (text.matches("\\d*")) {
        return change;
      }
      return null; // 如果用户输入不是数字，则不接受
    };
    TextFormatter<Integer> formatter = new TextFormatter<>(new IntegerStringConverter(), 0, filter);

    numRegionsField.setTextFormatter(formatter);
    numRegionsField.setDisable(false);

    TextArea textArea = new TextArea();
    textArea.setPromptText("输出结果"); // 设置提示文本

    // 设置文本输出框可以显示多行文本
    textArea.setPrefRowCount(3);
    textArea.setWrapText(true); // 设置文本自动换行
    CheckBox checkBox = new CheckBox("预分区");
    checkBox.setOnAction(event -> {
      // 当勾选框状态发生变化时
      numRegionsField.setDisable(!checkBox.isSelected());
    });
    CheckBox compressCheckBox = new CheckBox("SNAPPY压缩");
    ImageView statusIcon = new ImageView();
    statusIcon.setImage(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/success.png"))));
    statusIcon.setFitWidth(20); // 调整图标的宽度
    statusIcon.setFitHeight(20); // 调整图标的高度
    statusIcon.setVisible(true); // 默认隐藏状态

    grid.add(new Label("HBase 表名"), 0, 0);
    grid.add(tableNameField, 1, 0);
    grid.add(checkBox, 0, 1);
    grid.add(numRegionsField, 1, 1);
    grid.add(compressCheckBox, 2, 1);
    grid.add(textArea, 0, 2, 3, 2); // 将文本输出框跨越两列，并且占据两行
    grid.add(statusIcon, 4, 2);

    // 将布局添加到对话框
    createDialog.getDialogPane().setContent(grid);

    // 获取对话框按钮并设置事件处理
    Button loginButton = (Button) createDialog.getDialogPane().lookupButton(loginButtonType);
    loginButton.setOnAction(e -> {
      // 处理登录逻辑，获取username.getText()和password.getText()
      createDialog.setResult(tableNameField.getText());
      createDialog.close(); // 关闭对话框
    });
  }

  // 弹出查询对话框
  private void showSearchDialog(String tableName) {
    // 创建对话框
    Dialog<String> searchDialog = new Dialog<>();
    searchDialog.setTitle("查询");
    searchDialog.setHeaderText("查询 " + tableName);

    // 创建表格和列
    TableView<Map.Entry<String, String>> resultTable = new TableView<>();
    TableColumn<Map.Entry<String, String>, String> columnNameCol = new TableColumn<>("列名");
    TableColumn<Map.Entry<String, String>, String> columnValueCol = new TableColumn<>("值");

    columnNameCol.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getKey()));
    columnValueCol.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getValue()));

    columnNameCol.setPrefWidth(100);
    columnValueCol.setPrefWidth(300);

    // 为列设置单元格工厂
    columnValueCol.setCellFactory(param -> new PDFButtonCell());

    resultTable.getColumns().addAll(columnNameCol, columnValueCol);

    resultTable.setFixedCellSize(24);

    // 设置对话框按钮
    ButtonType searchButtonType = new ButtonType("查询", ButtonBar.ButtonData.OK_DONE);
    searchDialog.getDialogPane().getButtonTypes().addAll(searchButtonType, ButtonType.CANCEL);

    // 创建布局及控件
    GridPane grid = new GridPane();
    grid.setHgap(10);
    grid.setVgap(10);
    grid.setPadding(new Insets(20));

    TextField searchField = new TextField();
    searchField.setPromptText("请输入主键");

    TextField numRegionsField = new TextField();
    numRegionsField.setPromptText("请输入预分区数");
    // 创建一个整数格式化器，限制用户输入为整数
    UnaryOperator<TextFormatter.Change> filter = change -> {
      String text = change.getText();
      if (text.matches("\\d*")) {
        return change;
      }
      return null; // 如果用户输入不是数字，则不接受
    };
    TextFormatter<Integer> formatter = new TextFormatter<>(new IntegerStringConverter(), 0, filter);
    numRegionsField.setTextFormatter(formatter);
    numRegionsField.setDisable(false);

    CheckBox checkBox = new CheckBox("预分区");
    checkBox.setOnAction(event -> {
      // 当勾选框状态发生变化时
      numRegionsField.setDisable(!checkBox.isSelected());
    });

    grid.add(new Label("row key:"), 0, 0);
    grid.add(searchField, 1, 0);
    grid.add(checkBox, 0, 1);
    grid.add(numRegionsField, 1, 1);
    grid.add(resultTable, 0, 2, 6, 1);

    // 将布局添加到对话框
    searchDialog.getDialogPane().setContent(grid);

    // 获取对话框按钮并设置事件处理
    Button searchButton = (Button) searchDialog.getDialogPane().lookupButton(searchButtonType);

    EventHandler<ActionEvent> eventFilter = event -> {
      String rowKey = searchField.getText();
      System.out.println("table name: " + tableName);
      System.out.println("row key: " + rowKey);
      Map<String, String> result = HBaseMain.getMapResultByRowKey(tableName, rowKey);
      // 清空表格数据
      resultTable.getItems().clear();
      // 添加查询结果到表格中
      resultTable.getItems().addAll(result.entrySet());
      event.consume();
    };

    searchButton.addEventFilter(ActionEvent.ACTION, eventFilter);

    // 显示对话框
    searchDialog.showAndWait();
  }

  // 自定义单元格工厂类
  private static class PDFButtonCell extends TableCell<Map.Entry<String, String>, String> {
    private final Button pdfButton;
    private final Button base64Button;

    PDFButtonCell() {
      // PDF 按钮
      ImageView pdfIcon = new ImageView(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/pdf.png"))));
      pdfIcon.setFitWidth(16);
      pdfIcon.setFitHeight(16);

      pdfButton = new Button("", pdfIcon);
      pdfButton.setStyle("-fx-background-color: transparent; -fx-border-color: transparent;");
      pdfButton.setOnMouseEntered(event -> pdfButton.setCursor(Cursor.HAND));
      pdfButton.setOnAction(event -> {
        Object item = getTableRow().getItem();
        if (item instanceof Map.Entry) {
          String columnName = (String) ((Map.Entry<?, ?>) item).getKey();
          File pdf = getFileFromBackend(columnName);
          if (pdf != null) {
            displayPDF(pdf);
          }
        }
      });

      // Base64 按钮
      base64Button = new Button("Export Base64");
      base64Button.setStyle("-fx-background-color: transparent; -fx-border-color: transparent;");
      base64Button.setOnMouseEntered(event -> base64Button.setCursor(Cursor.HAND));
      base64Button.setOnAction(event -> {
        Object item = getTableRow().getItem();
        if (item instanceof Map.Entry) {
          String columnName = (String) ((Map.Entry<?, ?>) item).getKey();
          File file = HBaseMain.getFileFromBackend(columnName);
          if (file != null) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("Base64 Export");
            alert.setHeaderText("Base64 content exported");
            alert.setContentText("File saved to: " + file.getAbsolutePath());
            alert.showAndWait();
          }
        }
      });
    }

    @Override
    protected void updateItem(String item, boolean empty) {
      super.updateItem(item, empty);
      if (empty || item == null) {
        setGraphic(null);
      } else {
        if ("PDF".equals(item)) {
          setGraphic(pdfButton);
        } else if (item.contains("Base64 Encoded")) {
          setGraphic(base64Button);
        } else {
          setText(item);
          setGraphic(null);
        }
      }
    }

    private void displayPDF(File pdf) {
      PDFDisplayer displayer = new PDFDisplayer();
      Scene scene = new Scene(displayer.toNode(), 800, 600);
      Stage stage = new Stage();
      stage.setTitle("PDF Viewer");
      stage.setScene(scene);
      stage.setResizable(false);
      stage.show();
      try {
        displayer.loadPDF(pdf);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }

    // 模拟从后台获取 PDF 字节数组的方法，需要替换为实际的后台调用逻辑
    private File getFileFromBackend(String columnName) {
      // TODO: 实现从后台获取 PDF 字节数组的逻辑
      return HBaseMain.getFileFromBackend(columnName);
    }
  }
}
